<?php
/**
#模板目录
define("TPL_DIR", $this->application . "/template/default");
#模板编译目录
define("TPL_COMPILE_DIR", $this->application."/data/compile");
#模板编译文件的前缀
define("TPL_ID", $this->application);

//对PHP,HTML压缩,去掉HTML注释
define("TPL_ZIP_PHP", false);
define("TPL_ZIP_HTML", false);
//每次判断一个模板
define("TPL_CHECK", true);
//强制编译模板
define("TPL_FORCE_COMPILE", true);

$tpl = new tpl
$tpl->setup();
	OR
#实例化模板引擎,并初始化
$this->tpl->setup();

依赖 router 中的 url , _url 等几个函数
*/
class Tpl
{
	protected $vars = array();	//模板变量
	protected $left_delimiter = '{';//左右标记
	protected $right_delimiter = '}';
	protected $template_dir = 'template/default';	//文件目录,源文件目录
	protected $cache_dir = 'data/cache';		//缓存目录
	protected $compile_dir = 'data/compile';		//编译后文件所保存的目录
	protected $compile_id = 'default';		//编译ID
	protected $check = true;	//是否自动更新

	protected $zip_php = false;		//压缩PHP代码
	protected $zip_html = false;		//去掉HTML注释

	protected $force_compile = 0;		//强制编译

	protected $plugs_list = array(
	'html_options','html_select',
	'html_radios',
	'html_text',
	'html_textarea',
	'html_checkbox',
	'html_js',
	'html_css',
	'html_selects',
	);
	#注册函数
	protected $functionList = array(
	);
	#对象函数
	protected $objectList = array(
	);

	function __construct($config = array())
	{
		if(is_array($config))
		{
			foreach($config as $k => $v)
			{
				$this->$k = $v;
			}
		}
		
		#注册模板 模板函数 => 函数
		$this->registerFunction('url', 'router::_tpl_url');
		$this->registerFunction('_url', 'router::_tpl__url');
		//$this->registerFunction('C', 'Z::_tpl_c');
		$this->registerFunction('editor', 'router::_tpl_editor');
	}
	function setup()
	{
		
		$tpl = getconfig('tpl');
		$tpl['template_dir'] = APPPATH . '/' .getconfig('dir_view') . '/'.getconfig('template_dir');
		$tpl['compile_id'] = getconfig('template_dir');

		
		#模板配置并实例化
		/**
		
		$tpl_config = array(
		'template_dir'	=> TPL_DIR,
		'compile_dir'	=> TPL_COMPILE_DIR,
		'compile_id'	=> TPL_ID,
		'check'	=> TPL_CHECK,
		'zip_php'	=> TPL_ZIP_PHP,
		'zip_html'	=> TPL_ZIP_HTML,
		'force_compile'	=> TPL_FORCE_COMPILE,
		);
		foreach($tpl_config as $k => $v)
		{
			$this->$k = $v;
		}*/

		
		foreach($tpl as $k => $v)
		{
			$this->$k = $v;
		}
		
		$this->compile_dir = str_replace('\\','/', $this->compile_dir);
		return $this;
	}
	function setConfig($k,$v)
	{
		$this->$k = $v;
		return $this;
	}
	#注册
	function registerFunction($tplFunction, $function)
	{
		$this->functionList[$tplFunction] = $function;
	}
	function registerObject($tplFunction, &$object)
	{
		$this->objectList[$tplFunction] = &$object;
	}
	function getVar($name)
	{
		return $this->vars[$name];
	}
	function assign($name, $value)
	{
		$this->vars[$name] = $value;
	}
	function display($path)
	{
		
		
		extract($this->vars);
		extract($this->objectList);

		
		$compilePath = $this->compile_dir . '/'. $this->compile_id . '^' . str_replace('/', '_', $path);


		if ($this->force_compile || !file_exists($compilePath))
		{
			$this->init($path);
			include_once($compilePath);
			return true;
		}
		if ($this->check && is_file($this->template_dir . '/' . $path) && filemtime($compilePath) < filemtime($this->template_dir . '/' . $path))
		{
			$this->init($path);
			include_once($compilePath);
			return true;
		}

		include_once($compilePath);
		return true;
	}
	function init($path)
	{
		if(!is_file($abs_path = $this->template_dir . '/' . $path))
		{
			$_msg = "模板文件:{$abs_path}不存在";
			if(getconfig('kupe_status') == 'develop')
			{
				$_msg .= "<br>\n由于这是开发模式,自动创建模板文件:{$abs_path}";
				load::loadClass("help")->makeTemplate($abs_path);
			}
			load::loadClass('help')->show($_msg);
		}
		
		$content = file_get_contents($this->template_dir . '/' . $path);
		#找出内部include
		preg_match_all('/{include\s*file=[\"|\'|](.*)[\"|\'|].*}/isU', $content, $rec);
		#编译主文件
		$content = $this->compile($content);

		



		$copyright = "<?php \n/*\n文件名:{$path}\n编译日期:".date('Y-m-d H:i:s', time())."\n文件大小:".round(strlen($content)/1024, 3)."KB\n作者:阳升工作室, http://www.kupebank.com QQ:124181646*/\n ?>";
		file_put_contents($this->compile_dir . '/' . $this->compile_id . '^' . str_replace('/', '_', $path) , $copyright . $content);

		#编译主文件中的include
		$includes = array_unique($rec[1]);



		if (is_array($includes) && count($includes) > 0)
		{			
			foreach ($includes as $k => $v)
			{
				//补丁:  转成小写2012年4月18日 17:20:22 程序编写by:边缘狂人 QQ:124181646
				$includes[$k] = $v = strtolower($v);

				if (!file_exists($this->template_dir . '/' . $v))
				{
					exit("模板文件：". $this->template_dir . '/' . $v  . "不存在");
				}
				if ($path == $v)
				{
					exit("死循环调用,文件名:<b>{$v}</b>");
				}
				#子文件编译后,如果文件存在,不再重新编译
				/*if (!$this->force_compile && file_exists($this->compile_dir . '/' . $this->compile_id . '^' . ucfirst(str_replace('/', '_', $v))))
				{
					continue;
				}*/
				$this->init($v);
			}
		}
		return true;
	}
	function compile($content)
	{
	
		
		//$content = 'base href="{$APP_BASE}/" {*fdsafdsa$ dfsafdsfds*} <!--fdsaffdsa-->';
		#去掉注释
		$content = preg_replace('/\{\*.*\*}/isU', '', $content);

		//分隔出无编译的HTML代码
		preg_match_all('/{html}(.+){\/html}/isU', $content,$noparse);

		$APP_TIME = time();

		if(isset($noparse[1]))
		{
			foreach($noparse[1] as $k => $v)
			{
				$content = str_replace('{html}'.$v.'{/html}', "#".$APP_TIME."_{$k}", $content);
			}
		}


		#去掉HTML注释
		if ($this->zip_html)
		{
			$content = preg_replace('/<!--.*-->/isU', '', $content);
		}

		#{if $aaa.bbb.cccc} 变量不带空格 一唯数组
		$content = preg_replace('/\$(\w+)\.(\w+)([})\s+])/isU', '$$1["$2"]$3', $content);
		#支持变量 $var.key1.key2 {if $aaa.bbb.cccc}  变量不带空格
		$content = preg_replace('/\\$(\w+)\.(\w+)\.(\w+)([})\s+])/isU', '$$1["$2"]["$3"]$4', $content);

		#支持赋值
		$content = preg_replace('/\{(\$\w+\s*=.+)}/sU', '<?php $1;?>', $content);


		#支持变量
		$content = preg_replace('/\{\$(.+)}/sU', '<?php echo $$1;?>', $content);
		#支持常量
		$content = preg_replace('/\{\#(.+)}/sU', '<?php echo $1;?>', $content);

		#支持IF
		#方案二
		/*$content = preg_replace('/\{if(.+)}(.*){else}(.*){\/if}/isU', '<?php if($1){?> $2 <?php }else{ ?> $3 <?php } ?>', $content);
		$content = preg_replace('/\{if(.+)}/isU', '<?php if($1){?>', $content);*/

		$content = preg_replace('/\{if(.+)}/isU', '<?php if($1){?>', $content);
		$content = preg_replace('/\{elseif(.+)}/isU', '<?php }elseif($1){?>', $content);
		$content = str_replace(array('{else}'), array('<?php }else{?>'), $content);

		#支持FOREACH
		$content = preg_replace('/\{foreach(.+)}/isU', '<?php foreach($1){?>', $content);


		#支持for
		$content = preg_replace('/\{for(.+)}/isU', '<?php for($1){?>', $content);

		#支持　{php}
		$content = preg_replace('/{php}(.+){\/php}/isU', '<?php $1 ?>', $content);
		#支持　{while}
		$content = preg_replace('/\{while(.+)}/isU', '<?php while($1){?>', $content);



		#支持include
/*		$content = preg_replace('/{include\s*file=[\"|\'|](.+)[\"|\'|]}/isU', '<?php include("'.$this->compile_dir . '/' . $this->compile_id . '^' . '$1"); ?>', $content);*/

		$content = preg_replace_callback('/{include\s+(.*)}/isU', array($this,'setInclude'), $content);


		#结尾标记
		$content = str_replace(array('{/if}', '{/for}', '{/foreach}', '{/while}'), '<?php } ?>', $content);




		#支持插件
		foreach ($this->plugs_list as $v)
		{
			$this->_tmp = '$this->' . $v;
			/*			$content = preg_replace('/{('. $v .')\s(.*)}/isU', '<?php $this->$1(\'$2\'); ?>', $content);*/
			$content = preg_replace_callback('/{('. $v .')\s(.*)}/isU', array($this,'setPlugs'), $content);
		}

		#支持自定义函数
		foreach ($this->functionList as $k => $v)
		{
			$this->_tmp = "echo {$v}";
			$content = preg_replace_callback('/{('. $k .')(.*)}/isU', array($this,'setPlugs'), $content);
		}

		#支持自定义类
		foreach ($this->objectList as $k => $v)
		{
			$className = get_class($v);
			$this->object[$className] = $v;
		//	$this->_tmp = "\$this->object['".$className."']->";
		//	$content = preg_replace_callback('/{('. $k .')(.*)}/sU', array($this,'setPlugs'), $content);
			$content = preg_replace("/{run:(.+)}/isU", "<?php \$1;?>", $content);
		}

		/*
		run: 表示 ***
		: 表示 echo ****
		> 表示 $this->
		:> 表示 echo $this->
		*/
		$content = preg_replace("/{run:(.+)}/isU", "<?php \$1;?>", $content);
		$content = preg_replace("/{:>(.+)}/isU", "<?php echo \$this->\$1;?>", $content);
		$content = preg_replace("/{:(.+)}/isU", "<?php echo \$1;?>", $content);
		$content = preg_replace("/{>(.+)}/isU", "<?php \$this->\$1;?>", $content);


		//$this->object
		//unset($this->functionList, $this->objectList, $this->_tmp);


		//组合无编译的HTML代码
		if(isset($noparse[1]))
		{
			foreach($noparse[1] as $k => $v)
			{
				$content = str_replace("#".$APP_TIME."_{$k}", $v, $content);
			}
		}

		#合并PHP标记
		$content = preg_replace('/\?>\s*<\?php/is', '', $content);
		#压缩PHP代码
		if ($this->zip_php)
		{
			$content = preg_replace('/\s+/isU', ' ', $content);
		}
		return $content;
	}

	/*
	支持系统插件
	*/
	function setPlugs($p)
	{
		//$p[2] = preg_replace('/#\$(.*)#/isU', '{$$1}', $p[2]);	p($p[2], 1);
		$p[2] = $this->InitValue($p[2]);

		@eval("\$var = {$p[2]} ; ");		//当使用变量时,会有一个 变量未定义的错误,暂时屏B

		if (isset($var['assign']))
		{
			$this->_tmp = '$' . $var['assign'] . '=' . $this->_tmp;
		}
		if (!isset($var['func']))
		{
			//$this->_tmp .= $var['func'];
			 $var['func'] = '';
		}

		$str = '<?php ';
		//$str .= "{$this->_tmp}{$p[1]}(";
		$str .= "{$this->_tmp}{$var['func']}(";
		$str .= $p[2];
		$str .= "); ?>";
		return $str;
	}

	function setInclude($p)
	{

		//$C = getconfig();
		extract($this->vars);	//这么做,是为了支持变量
		$var = $this->InitValue($p[1]);
		eval("\$var = $var ; ");
		$file = $var['file'];
		//补丁: file 转成小写2012年4月18日 17:20:22 程序编写by:边缘狂人 QQ:124181646
		$file = strtolower($file);



		unset($var['file']);
		$out = '<?php ';
		foreach ($var as $k => $v)
		{
			$out .= "\${$k}=\"".addslashes($v)."\";";
		}
		$out .= 'include("'.$this->compile_dir . '/' . $this->compile_id . '^' .$file . '"); ?>';
		return $out;
	}

	function InitValue($value)
	{
		//preg_match_all('/(.*)=(\S*)/isU', $value, $rec);
		//p($rec);
		$value = preg_replace('/\s+(\w+)\s*=\s*/isU', ',\'$1\'=>', ' ' . trim($value));
		$value = substr($value, 1);
		return "array({$value})";
	}
	######################################################################################
	/*
	# 模板支持SELECT
	$patameter = array(
	'name',
	'id',
	'value',
	'other',
	)
	*/
	function html_select($parameter,$return = false)
	{
		extract($parameter);
		@$out = "<select name='{$name}' id='{$id}' {$other}>";
		if (isset($default))
		{
			$out .= "<option value=''>{$default}</option>";
		}
		foreach ($options as $k => $v)
		{
			if ($value && $k == $value)
			{
				$out .= "<option value='{$k}' selected>{$v}</option>";
			}
			else
			{
				$out .= "<option value='{$k}'>{$v}</option>";
			}
		}
		$out .= "</select>";
		if($return)
		{
			return $out;
		}
		echo $out;
		//extract($this->InitValue($parameter));
	}
	/*
	数组格式
	array(
		array('title' => 'xxxx','sub' => array('id' => $value, 'id2' => $value2)),
		array('title' => 'xxxx','sub' => array('id' => $value, 'id2' => $value2)),
		array('title' => 'xxxx','sub' => array('id' => $value, 'id2' => $value2)),
		array('title' => 'xxxx','sub' => array('id' => $value, 'id2' => $value2)),
	)
	*/
	function html_selects($parameter,$return = false)
	{
		extract($parameter);
		@$out = "<select name='{$name}' id='{$id}' {$other}>";
		if (isset($default))
		{
			$out .= "<option value=''>{$default}</option>";
		}
		foreach ($options as $k => $v)
		{
			if(isset($v['title']))
			{
				$out .= "<optgroup label='{$v['title']}'>";
			}

			foreach($v['sub'] as $kk => $vv)
			{
				if ($value && $kk == $value)
				{
					$out .= "<option value='{$kk}' selected>{$vv}</option>";
				}
				else
				{
					$out .= "<option value='{$kk}'>{$vv}</option>";
				}
			}
			if(isset($v['title']))
			{
				$out .= "</optgroup>";
			}
		}
		$out .= "</select>";
		if($return)
		{
			return $out;
		}
		echo $out;
		//extract($this->InitValue($parameter));
	}
	#SELECT 别名
	function html_options($parameter)
	{
		$this->html_select($parameter);
	}
	#
	function html_radios($parameter)
	{
		//$separator
		extract($parameter);
		if (!isset($sep))
		{
			$sep = '&nbsp;&nbsp;';
		}
		$out = '';
		$i = 0;
		if(!isset($label))
		{
			$label = 1;
		}
		foreach ($options as $k => $v)
		{
			$out .= "<input type='radio' value='$k' name='{$name}' title='{$v}' id='{$name}_{$i}'";
			if ($value == $k)
			{
				$out .= " checked";
			}
			$out .= '>';
			if($label)
			{
				$out .= "<label for='{$name}_{$i}' class='__{$name}__'>$v</label>";
			}
			$out .= $sep;
			$i++;
		}
		echo $out;
	}
	function html_checkbox($parameter)
	{
		extract($parameter);
		if (!isset($sep))
		{
			$sep = '&nbsp;&nbsp;';
		}
		$out = '';
		$i = 0;
		if (!isset($checked))
		{
			$checked = array();
		}
		if(!isset($text_before))
		{
			#文字在前面
			$text_before = 1;
		}
		if(isset($value))
		{
			$checked = $value;
		}
		foreach ($options as $k => $v)
		{
			$out .= "<span class='checkbox_{$name}'>";
			if($text_before)
			{
				$out .= "<label for='{$name}_{$i}'>$v</label>";
			}
			$out .= "<input type='checkbox' value='$k'  title='{$v}' name='{$name}[]' id='{$name}_{$i}'";
			if (in_array($k, $checked))
			{
				$out .= " checked";
			}
			$out .= '>';

			if(!$text_before)
			{
				$out .= "<label for='{$name}_{$i}'>$v</label>";
			}
			$out .= $sep .'</span>';

			$i++;
		}
		echo $out;
	}
	function html_text($parameter)
	{
		extract($parameter);
		!isset($id) && $id=$name;
		echo "<input type='text' value='{$value}' name='{$name}' id='{$id}' $other >";
		//echo $out;
	}
	function html_textarea($parameter)
	{
		extract($parameter);
		!isset($id) && $id=$name;
		echo "<textarea name='{$name}' id='{$id}' $other >{$value}</textarea>";
		//echo $out;
	}
	function html_js($parameter)
	{
		extract($parameter);
		echo "<script src='{$src}' type='text/javascript'></script>";
		// $out;
	}
	function html_css($parameter)
	{
		extract($parameter);
		echo '<link rel="stylesheet" rev="stylesheet" href="'.$src.'" type="text/css" />';
		//echo $out;
	}
	function __destruct()
	{
		#DEBUG
		//p(get_included_files());
	}
}